#if !defined(_ASPRITE_H_)
#define _ASPRITE_H_

#include "ASpriteModel.h"
#include "ASpriteContainer.h"
#include "AAnimateObject.h"
#include "AEvent.h"
#include "ASettings.h"

class CAStageLayer;
//#define _HandleState(nst, st) if (CAStringUtils::equal_nc(nst, #st)) _on##st();
typedef enum enumStateFlag
{
	SF_Begin,
	SF_Update,
}
EStateFlag;

#define _HandleState(nst, st, flag) if (nst == #st) _on_##st(flag);

typedef enum enumSpriteLifeState
{
	SLS_INIT,
	SLS_RUNNING,
	SLS_DYING,
	SLS_DIED,
}
ESpriteLifeState;

#define STATE_Init		"init"
#define STATE_Stand		"stand"
#define STATE_Fadein	"fadein"
#define STATE_Running	"running"
#define STATE_Wait		"waiting"
#define STATE_Dying		"dying"
#define STATE_Fadeout	"fadeout"
#define STATE_Idle		"idle"

typedef enum enumSpriteType
{
	ST_Frames,
	ST_Text,
}
ESpriteType;

class CASprite : public CCSprite, public CAAnimateObject, public CASpriteContainer
{
protected:
	ESpriteType	_type;

	void _onUpdateCurrentPose();

protected:
	//real parent
	CAStageLayer* _pLayer;
	//CASprite* _psprParent;
	//debug
	CAString _debugname;
	//resources
	CAString _modname;
	CAString _groupname;
	CASpriteModel* _model;

	//states
	CAString _state;
	ESpriteLifeState _inner_state;
	void _setInnerState(ESpriteLifeState ls);

	CASpriteModelPose* _currentPose;

#if defined(_DEBUG)
	CCPoint _posOffsetUsed;
	CASpriteModelPoseModifierKey _gameKeyUsed;
#endif
	//settings
	/*const, cocos issule*/ CASettings& _settings() 
	{
		_Assert(null != _model);
		return _model->settings(); 
	};

	//timer
	bool _bUseGlobalTimer;

	//real keys in 
	float	_z;
	float	_direction, _dirSin, _dirCos;
	float	_speed;
	CCRect	_rectLive;

	int _nControlOrder;
	bool _bIsTouchable;
	bool _isTouched(CAEventTouch* pet);

	CCSpriteFrame* _onAnimateUpdateFrame(ccTime timeNow);
	void _onAnimateUpdate(ccTime timeNow);

	virtual void _adjustPosition(CCPoint& pos) {}
public:
	static int counter;

	CASprite(CAStageLayer* player, const char* model);
	virtual ~CASprite(void);

	//void setSpriteTarget(CASprite* pspr) { _psprParent = pspr; };

	virtual void retain();
	virtual void release();
	//env
	//inline CCTexture2D* getTexture() { return _pTexture2D; }
	void setDebugName(const CAString& dname) { _debugname = dname; }
	const CAString& getDebugName() const { return _debugname; }

	const CAString& getResName() const { return _model->file(); }
	const CAString& getModName() const { return _modname; }
	
	void setGroupName(const CAString& name) 
	{ if (name.length() > 0) _groupname = name; }
	//default name is modname
	const CAString& getGroupName() const { return _groupname; } 
	
	const CAString& getTextureName() const;
	CAStageLayer* layer() { return _pLayer; }

	void setControlOrder(int order) { _nControlOrder = order; }
	int getControlOrder() const { return _nControlOrder; }

	void setTouchable(bool b) { _bIsTouchable = b; }
	bool isTouchable() const { return _bIsTouchable; }

	void setStringSettings(const map<CAString, CAString>* p);

	//poses
	virtual void switchPose(const CAString& pose);

	//states
	const CAString& getState() const { return _state; }
	void setState(const CAString& state);
	virtual void onBeforeStateChanging(const CAString& olds, const CAString& news);
	virtual void onStateChanged(const CAString& olds, const CAString& news);

	bool isRunning() const { return SLS_RUNNING == _inner_state; }
	bool isDied() const { return SLS_DIED == _inner_state; }

	inline CASpriteModelPose* getCurrentPose() { return _currentPose; }
	//do not remove me in this time, some action has not stop yet
	//we will do cleanup jobs in next round, in visit()
	inline void killMyself() 
	{ 
		if (_inner_state != SLS_DYING && _inner_state != SLS_DIED)
		{
			_setInnerState(SLS_DYING); 
		}
	};

	//this is a view area
	void setLiveArea(const CCRect& rect, bool bPercent = true);
	virtual inline void setMoveSpeed(float s) 
	{ 
		_speed = s; 
		_Assert(_speed > -999999999.0f && _speed < 999999999.0f);
	}
	inline float getMoveSpeed() const { return _speed; }
	inline void setZOrder(float z) { _z = z; }
	inline float getZOrder() const { return _z; }
	inline void setMoveDirection(float r)
	{ 
		_direction = r; 
		_dirCos = cos(A2R(r)); 
		_dirSin = -sin(A2R(r)); 
	}
	inline float getMoveDirection() const { return _direction; }
	//game bounding box
	CCRect getGameBoundingBox(bool b4Collid = false);
	//view bounding box
	CCRect getViewBoundingBox(bool b4Collid = false);

	bool isCollidWith(CASprite* pspr, bool bView = true);

	const CASpriteModelPoseModifierKey& getCombinedKey() { return _combinedKey; };

	void setUseGlobalTimer(bool use) { _bUseGlobalTimer = use; }

	virtual void onEnter();
	virtual void onUpdate();
	virtual void onExit();

	virtual void onTouched(CAEventTouch* pEvent) {};
	virtual void onTouchLeave(CAEventTouch* pEvent) {};

	virtual bool onEvent(CAEvent* pEvent);
};

#endif //_ASPRITE_H_
